package com.suncreate.commons;

import java.math.BigDecimal;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.suncreate.radarscan.dao.AlertEventEntityMapper;
import com.suncreate.radarscan.entity.AlertEventEntity;
import com.suncreate.radarscan.model.Lane;
import com.suncreate.radarscan.model.Radar;
import com.suncreate.radarscan.model.RawRadarData;
import com.suncreate.radarscan.model.Road;
import com.suncreate.radarscan.model.TargetRadarData;
import com.suncreate.radarscan.service.AlertEventDetectService;

public class AlertEventDetectThread extends Thread {
	
	private AlertEventEntityMapper alertEventDetectDao;

	//日志记录        
    private Logger logger = LoggerFactory.getLogger(AlertEventDetectThread.class);
    
	private Radar radar;
	
	private Road road;
	
//	private LinkedBlockingQueue<RawRadarData> rawDataQueue = new LinkedBlockingQueue<RawRadarData>();
	
	//用于保存检测区域内最新的目标数据
	private Map<Integer,TargetRadarData> targetMap = new HashMap<Integer,TargetRadarData>();
	
	//暂存rawRadarData对应的targetRadarData
	private TargetRadarData targetData;
	
	@Override
	public void run() {
		logger.debug("开始事件检测，检测的雷达序列号为：" + radar.getRadarNo());
		RawRadarData rawData = null;
		while(true) {
			try {
				rawData = AlertEventDetectService.rawDataQueueMap.get(radar.getRadarNo()).take();
				logger.debug("取出雷达原始数据为:" + rawData.toString() + ",雷达序列号为:" + radar.getRadarNo());
				
				//获取rawData所在车道号，车道编号从左到右依次从1开始编号
				int laneNum = laneDetect(rawData);
				
				if(0 == laneNum) {
					logger.debug("此原始数据所在道路号为非法值，不能判断，为非法数据,原始数据为：" + rawData.toString());
					continue;
				}
				
				//获取rawData所在车道信息
				Lane lane = road.getLanes().get(laneNum-1);
				logger.debug("原始雷达数据为:" + rawData.toString() + ",其所在的车道号为:" + laneNum + ",所在的道路信息为:" + lane.toString());
				
				/**
				 * 逆行检测：判断目标是否逆行(逆行事件类型为0)
				 * 方法是：如果满足1.当前目标的Y轴向速度为正并且目标所在道路的方向为反向  或2.当前目标的Y轴向速度为负并且目标所在道路的方向为正向
				 *       则认为此目标为逆行
				 */
				logger.debug("开始逆行事件检测，原始数据为：" + rawData.toString());
				if((rawData.getySpeed()>0 && !lane.isRightDirection()) || (rawData.getySpeed()<0 && lane.isRightDirection()) ) {
					//临时保存异常事件
					AlertEventEntity alertEvent = new AlertEventEntity();
					alertEvent.setId(UUID.randomUUID().toString().replace("-", ""));
					alertEvent.setDistance(new BigDecimal(Float.toString(rawData.getyDistance())));
					alertEvent.setEventContent("逆行事件产生时目标所在车道号为：" + laneNum);
					alertEvent.setEventFeatures("禁止逆行");
					alertEvent.setEventTime(rawData.getTime());
					alertEvent.setEventType(0);
					alertEvent.setEventNo(rawData.getiTargetNum());
					alertEvent.setEventType(rawData.getiTargetType());
					alertEvent.setSpeed(new BigDecimal(Float.toString(rawData.getySpeed())));
					
					/*
					 * 此处将逆行事件插入到dr3_event表中
					 */
					alertEventDetectDao.insert(alertEvent);
					logger.debug("将逆行事件插入到dr3_event表中，逆行事件详细信息为：" + alertEvent.toString() + ",对应的原始数据为：" + rawData.toString());
				}else {
					logger.debug("该原始数据不是逆行事件，对应原始数据为：" + rawData.toString());
				}
				logger.debug("逆行事件检测结束，原始数据为：" + rawData.toString());
				
				/**
				 * 超速检测：判断目标是否超速（事件类型为1）
				 * 方法是：如果目标正向且Y轴向速度大于所在车道的最高速度
				 *       则认为是超速。（备注：我们将目标速度<0认为是逆行，即使逆行的速度大于所在车道的最高速度，仍然认为只是逆行，而不是超速）
				 */
				logger.debug("开始超速事件检测，原始数据为：" + rawData.toString());
				if(rawData.getySpeed()>lane.getMaxSpeed()) {
					AlertEventEntity alertEvent = new AlertEventEntity();
					alertEvent.setId(UUID.randomUUID().toString().replace("-", ""));
					alertEvent.setDistance(new BigDecimal(Float.toString(rawData.getyDistance())));
					alertEvent.setEventContent("超速事件产生时目标所在车道号为：" + laneNum);
					alertEvent.setEventFeatures("此车道限速：" + lane.getMaxSpeed() + "Km/h");
					alertEvent.setEventTime(rawData.getTime());
					alertEvent.setEventType(1);
					alertEvent.setEventIllegalValue(new BigDecimal(Float.toString(rawData.getySpeed())));
					alertEvent.setEventIllegalValue(new BigDecimal(Double.toString(lane.getMaxSpeed())));
					alertEvent.setEventNo(rawData.getiTargetNum());
					alertEvent.setEventType(rawData.getiTargetType());
					alertEvent.setSpeed(new BigDecimal(Float.toString(rawData.getySpeed())));
					
					/*
					 * 此处将超速事件插入到dr3_event表中
					 */
					alertEventDetectDao.insert(alertEvent);
					logger.debug("将超速事件插入到dr3_event表中，超速事件详细信息为：" + alertEvent.toString() + ",对应的原始数据为：" + rawData.toString());
				}else {
					logger.debug("该原始数据不是超速事件，原始数据为：" + rawData.toString());
				}
				logger.debug("超速事件检测结束，原始数据为：" + rawData.toString());
				
				/**
				 * 非法变道检测：判断目标是否存在非法变道（事件类型为2）
				 * 方法是：判断目标当前时刻与上一时刻所在车道号是否一致，如果一致则认为没有非法变道，否则：
				 *       如果当前车道号小于上一时刻车道号并且当前车道的右侧为实线，
				 *       或者当前车道号大于上一时刻车道号并且当前车道的左侧为实线，则认为是非法变道
				 */
				/*
				 *A.如果目标状态列表中没有当前目标编号，则无法判断，只要将当前目标加入到目标状态列表中即可
				 *B.如果目标状态列表中存在当前编号，并且与当前目标的时间相差50毫秒，则认为目标状态列表中的数据不可用，属于没有正常移除的非法数据，
				 *此时，只需要将当前目标更新至目标状态列表中即可，此时由于没有上一时刻的状态信息，也无法完成判断
				 * (这样做的依据是认为不可能前一辆车驶出检测去，立马就有一辆车进入检测区，并且编号使用跟驶出的车一样的编号，这部分还需要确认，检测区中目标如何编号？）
				 */
				logger.debug("开始非法变道事件检测，原始数据为：" + rawData.toString());
				if( !targetMap.containsKey(rawData.getiTargetNum()) ) {
					
					targetMap.put(rawData.getiTargetNum(),this.targetData);
					logger.debug("目标状态列表中没有此目标的状态信息，无法进行非法变道检测，已将该目标添加到状态列表中，供下次判断使用");
					continue;
					
				}else {
					try {
						Long historyTime = targetMap.get(rawData.getiTargetNum()).getTime();
						Long nowTime = rawData.getTime();
						long between = nowTime - historyTime;
						if(Math.abs(between) >100) {
							targetMap.put(rawData.getiTargetNum(), this.targetData);
							logger.debug("目标状态列表中的数据已经过时(与当前目标超过100毫秒)，无法进行非法变道检测,已将该目标添加到状态列表中，供下次判断使用");
							continue;
						}else {
							if( ( laneNum < targetMap.get(rawData.getiTargetNum()).getRoadNum() && lane.isRealLineRight()) 
								  ||( laneNum > targetMap.get(rawData.getiTargetNum()).getRoadNum() && lane.isRealLineLeft() )) {
								AlertEventEntity alertEvent = new AlertEventEntity();
								alertEvent.setId(UUID.randomUUID().toString().replace("-", ""));
								alertEvent.setDistance(new BigDecimal(Float.toString(rawData.getyDistance())));
								alertEvent.setEventContent("由车道号为：" + targetMap.get(rawData.getiTargetNum()).getRoadNum() + "的车道非法变道至车道号为：" + laneNum + "的车道。");
								alertEvent.setEventFeatures("非法变道");
								alertEvent.setEventTime(rawData.getTime());
								alertEvent.setEventType(2);
								alertEvent.setRadarNo(rawData.getRadarNo());
								
								alertEvent.setEventNo(rawData.getiTargetNum());
								alertEvent.setEventType(rawData.getiTargetType());
								alertEvent.setSpeed(new BigDecimal(Float.toString(rawData.getySpeed())));
								/**
								 * 插入到数据库
								 */
								alertEventDetectDao.insert(alertEvent);
								logger.debug("将非法变道事件插入到dr3_event表中，非法变道事件详细信息为：" + alertEvent.toString() + ",对应的原始数据为：" + rawData.toString());
							}else {
								logger.debug("该原始数据不是非法变道事件，原始数据为：" + rawData.toString());
							}
						}
						targetMap.put(rawData.getiTargetNum(), this.targetData);
					} catch (Exception ex) {
						logger.error(ex.getMessage(),ex);
					}
				}
				logger.debug("非法变道事件检测结束，原始数据为：" + rawData.toString());
			} catch (Exception ex) {
				logger.error("",ex);
			}
		}
	}
	
	//判断目标所在车道,车道从左到右依次从1开始编号
	public int laneDetect(RawRadarData rawData) {
		int laneNum = 0;
		double x = this.radar.getxAxe() + rawData.getxDistance();
		double xAxe = this.road.getxAxe();
		List<Lane> lanes = this.road.getLanes();
		
		for(int i=0;i<lanes.size();i++) {
			if( (x >= xAxe) && (x <= xAxe+lanes.get(i).getWidth()) ) {
				laneNum =  i+1;
				
				//将rawData转化为TargetRadarData
				TargetRadarData targetRadarData = new TargetRadarData();
				targetRadarData.setAction(rawData.getiTargetStatus());
				targetRadarData.setxDistance(rawData.getxDistance());
				targetRadarData.setyDistance(rawData.getyDistance());
				targetRadarData.setDistance(rawData.getyDistance());
				targetRadarData.setNumber(rawData.getiTargetNum());
				targetRadarData.setSpeed(rawData.getySpeed());
				targetRadarData.setxSpeed(rawData.getxSpeed());
				targetRadarData.setySpeed(rawData.getySpeed());
				targetRadarData.setTargetType(rawData.getiTargetType());
				targetRadarData.setTotalCount(rawData.getiTargetSum());
				targetRadarData.setX(AlertEventDetectService.radarMap.get(rawData.getRadarNo()).getxAxe() + rawData.getxDistance());
				targetRadarData.setY(AlertEventDetectService.radarMap.get(rawData.getRadarNo()).getxAxe() + rawData.getyDistance());
				targetRadarData.setRoadNum(laneNum);
				targetRadarData.setTime(rawData.getTime());
				this.targetData = targetRadarData;
				
				return laneNum;
			}else {
				xAxe +=lanes.get(i).getWidth();
			}
		}
		
		return laneNum;
	}

	
	//测试环境用，以后删掉即可
	public int laneDetectTest(RawRadarData rawData) {
		int laneNum = 0;
//		double x = this.radar.getxAxe() + rawData.getxDistance();
		double y = this.radar.getyAxe() + rawData.getyDistance();
		double xAxe = this.road.getxAxe();
		List<Lane> lanes = this.road.getLanes();
		
		for(int i=0;i<lanes.size();i++) {
			if( (y >= xAxe) && (y <= xAxe+lanes.get(i).getWidth()) ) {
				laneNum =  i+1;
				
				//将rawData转化为TargetRadarData
				TargetRadarData targetRadarData = new TargetRadarData();
				targetRadarData.setAction(rawData.getiTargetStatus());
				targetRadarData.setxDistance(rawData.getxDistance());
				targetRadarData.setyDistance(rawData.getyDistance());
				targetRadarData.setDistance(rawData.getyDistance());
				targetRadarData.setNumber(rawData.getiTargetNum());
				targetRadarData.setSpeed(rawData.getySpeed());
				targetRadarData.setxSpeed(rawData.getxSpeed());
				targetRadarData.setySpeed(rawData.getySpeed());
				targetRadarData.setTargetType(rawData.getiTargetType());
				targetRadarData.setTotalCount(rawData.getiTargetSum());
				targetRadarData.setX(AlertEventDetectService.radarMap.get(rawData.getRadarNo()).getxAxe() + rawData.getxDistance());
				targetRadarData.setY(AlertEventDetectService.radarMap.get(rawData.getRadarNo()).getxAxe() + rawData.getyDistance());
				targetRadarData.setRoadNum(laneNum);
				targetRadarData.setTime(rawData.getTime());
				this.targetData = targetRadarData;
				
				return laneNum;
			}else {
				xAxe +=lanes.get(i).getWidth();
			}
		}
		
		return laneNum;
	}
	
	public AlertEventDetectThread(Radar radar, Road road,AlertEventEntityMapper alertEventDao) {
		super();
		this.radar = radar;
		this.road = road;
		this.alertEventDetectDao = alertEventDao;
	}

}
